package application;

//import java.util.Iterator;
//import com.hp.hpl.jena.query.ARQ;
//import com.hp.hpl.jena.query.Query;
//import com.hp.hpl.jena.query.QueryExecution;
//import com.hp.hpl.jena.query.QueryExecutionFactory;
//import com.hp.hpl.jena.query.QueryFactory;
//import com.hp.hpl.jena.query.QuerySolution;
//import com.hp.hpl.jena.query.ResultSetFormatter;
//import java.util.ArrayList;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ReadWrite;
import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.tdb.*;
import com.hp.hpl.jena.util.FileManager;
import com.vaadin.server.VaadinService;

import data.Celebrity;
import data.womenclothing.WomenClothing;
import data.womenclothing.apparel.Apparel;
import data.womenclothing.apparel.Dress;
import data.womenclothing.apparel.Shirt;
import data.womenclothing.apparel.trouser.Jeans;
import data.womenclothing.apparel.trouser.Pants;
import data.womenclothing.shoes.Boots;
import data.womenclothing.shoes.Occupational;
import data.womenclothing.shoes.Shoes;
import data.womenclothing.shoes.Slippers;
import data.womenclothing.shoes.heels.Heels;
import data.womenclothing.size.ApparelSize;
import data.womenclothing.size.ShoeSize;

public class Database {
	
	Dataset dataset;
	Model customers;
	Model dbpedia;
	Model linkedData;
	
	public Database(){
		//open TDB dataset
		String path = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();
		String directory = path+"\\WEB-INF\\data\\tdb";
		dataset = TDBFactory.createDataset(directory);
		
		//create model for dataset
	    customers = dataset.getNamedModel("customers");
	    dbpedia = dataset.getNamedModel("celebrities");
	    linkedData = dataset.getNamedModel("linked");
	    
	    String source1 = path+"\\WEB-INF\\data\\datasets\\customers.rdf";
		String source2 = path+"\\WEB-INF\\data\\datasets\\dbpedia_final.rdf";
		String source3 = path+"\\WEB-INF\\data\\datasets\\linkedCelebrities.nt";
		
		//insert the models to dataset
		FileManager.get().readModel(customers, source1);
		FileManager.get().readModel(dbpedia, source2);
		FileManager.get().readModel(linkedData, source3);
	}
	
	
	
	//query model for celebrities 
	public List<Celebrity> queryCelebrity(){
		
	   List<Celebrity> celebrities = new LinkedList<Celebrity>();
		   
	   //call dataset for write transaction
	   dataset.begin(ReadWrite.READ) ;
		  
	  
	   String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
	   							+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
	   							+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
	   							+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
	   							+ "PREFIX vocab: <http://localhost:2020/vocab/>"
	   							+ ""
	   		                    + "SELECT ?url1 ?url2 ?name ?surname (str(?customerID) as ?label) ?desc ?pict"
	   		                            + " {GRAPH arq:UnionGraph {?url1 <http://www.w3.org/2002/07/owl#sameAs> ?url2."
	   		                                                    + "?url1 v:given-name ?name."
	   		                                                    + "?url1 v:family-name ?surname."
	   		                                                    + "?url1 vocab:customer_customerId ?customerID."
	   		                                                    + "?url2 dbpedia-owl:abstract ?desc."
	   		                                                    + "?url2 dbpedia-owl:thumbnail ?pict.}} ";

	   
	   
	   Query query = QueryFactory.create(sparqlQueryString) ;
	   QueryExecution qexec = QueryExecutionFactory.create(query, dataset) ;
	   ResultSet results = qexec.execSelect() ;
	  
	   while (results.hasNext()){
		 
		   QuerySolution soln = results.nextSolution();
		   String name = soln.getLiteral("name").toString();
		   String surname = soln.getLiteral("surname").toString();
		   String description = soln.getLiteral("desc").toString();
		   String customerID = soln.getLiteral("label").toString();
		   String image = soln.getResource("pict").toString();
		   
		   Celebrity celebrity = new Celebrity (name+" "+surname,name,surname,description, customerID);
		   celebrity.setImage(image);
		   
		   celebrities.add(celebrity);
		   };
	 
	    
	  //end dataset
	   dataset.end();
			   
	   return celebrities;
	
	}
	
	public List<WomenClothing> queryClothes(Celebrity celebrity){
		
		LinkedList<WomenClothing> clothes = new LinkedList<WomenClothing>();
		String brand = "";
		
		String customerID = celebrity.getCustomerID();
		
		try{
			dataset.begin(ReadWrite.READ) ;
			
			String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
						+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
						+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
						+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
						+ "PREFIX vocab: <http://localhost:2020/vocab/>"
						+ "PREFIX gr: <http://purl.org/goodrelations/v1#>"
						+ ""
						+ "SELECT ?clothing ?type ?product "
						+ "(group_concat(distinct ?material;separator=',') as ?materials) "
						+ "(group_concat(distinct ?color;separator=',') as ?colors)"
						+ " ?brandName "
						+                              "{GRAPH arq:UnionGraph"
						+ "                               {?clothing vocab:customerownsclothing <http://localhost:2020/customer/"+customerID+">."
						+                                 "?clothing vocab:clothing_productSubType ?type."
						+                                 "?clothing vocab:clothing_rootId ?product."
						+                                 "OPTIONAL{"                               
						+                        	        "?hasMaterial vocab:clothinghasmaterial_clothingId ?clothing."
				        +                         	        "?hasMaterial vocab:clothinghasmaterial_hasMaterial ?material."
					    +                           	    "?hasColor vocab:clothinghascolor_clothingId ?clothing."
				        +                                 	"?hasColor vocab:clothinghascolor_hasColor ?color."
				        +                                 	"?product vocab:productorservice_hasBrand ?brand."
				        +                                 	"?brand gr:name ?brandName."
				        +                                 "}."
				        +                                 "}} GROUP BY ?clothing ?type ?product ?brandName" ;
	                 

			Query query = QueryFactory.create(sparqlQueryString) ;
			QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
			ResultSet results = qexec.execSelect() ;
			
			
			
			while (results.hasNext()){
				   
				List<String> materials = new LinkedList<String>();
				List<String> colors = new LinkedList<String>();
				   
				   QuerySolution soln = results.nextSolution();
				   String type = soln.getLiteral("type").toString();
				   String product = soln.getResource("product").toString();
				   String clothing = soln.getResource("clothing").toString();
				   
				   
				   if( soln.getLiteral("materials") != null ){
					   String material = soln.getLiteral("materials").toString();
					   materials.add(material);
				   }
				   if( soln.getLiteral("colors") != null ){
					   String color = soln.getLiteral("colors").toString();
					   colors.add(color);
				   }
				   if( soln.getLiteral("brandName") != null){
					   brand = soln.getLiteral("brandName").toString();
				   }
				   
				   if (type.equals("Apparel")){
					   clothes = queryApparel(clothing,materials,colors,brand);

				   }else{
					   clothes = queryShoes(clothing,materials,colors,brand,clothes);
				   }
				   
			
		   };   
			    
			  //end dataset 	 
			dataset.end();
			
		}catch(Exception e){
			
			e.printStackTrace();
		    System.out.println(e.toString());
		}		
		
		return clothes;
	}
	
 
	

	public LinkedList<WomenClothing> queryApparel(String clothing,List<String> materials,List<String> colors,String brand){
		
		LinkedList<WomenClothing> clothes = new LinkedList<WomenClothing>();
		List<ApparelSize> apparelSizes = new LinkedList<ApparelSize>();
		String sizeType = null;
		String sizeTypeID = null;
		String standardVal = null;
		String dimension = null;
		String sizeValue = null;
		String apparelURIOld = null;
		
		String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
				+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
				+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
				+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
				+ "PREFIX vocab: <http://localhost:2020/vocab/>"
				+ ""
				+ "SELECT ?subtype1 ?sizeType (str(?sizeTypeID) as ?IDlabel) ?standadtVal ?dimension ?apparel"
				+          "{GRAPH arq:UnionGraph {?apparel vocab:apparel_rootId <"+clothing+">."
						+                         "?apparel vocab:apparel_productSubType ?subtype1."
						+                         "OPTIONAL{"
						+                         "?apparel vocab:apparelhasapparelsize ?size."
						+                         "?size vocab:apparelsize_sizeStandardId ?standartID."
						+                         "?standartID vocab:sizestandard_sizeStandardValue ?standadtVal."
						+                         "?size vocab:apparelsize_sizeDimensionValue ?dimension."
						+                         "?size vocab:apparelsize_sizeType ?sizeType."
						+                         "?size vocab:apparelsize_sizeTypeId ?sizeTypeID."
						+                         "}."
						+                         "}}";
	           
	
		Query query = QueryFactory.create(sparqlQueryString) ;
		QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
		ResultSet results = qexec.execSelect() ;
		
		 while (results.hasNext()){
			 
			   QuerySolution soln = results.nextSolution();
			   
			   WomenClothing apparel = null;
			   String subtype = soln.getLiteral("subtype1").toString();
			   String apparelURI = soln.getResource("apparel").toString();
			   
			   
			   if( soln.getLiteral("sizeType") != null && soln.getLiteral("IDlabel") != null ){
				   sizeType = soln.getLiteral("sizeType").toString().toLowerCase();
				   sizeTypeID = soln.getLiteral("IDlabel").toString();
				   
				   sizeValue = queryApparelSize(sizeType,sizeTypeID);
			   }
			   if( soln.getLiteral("standadtVal") != null ){
				   standardVal = soln.getLiteral("standadtVal").toString();
			   }
			   if( soln.getLiteral("dimension") != null ){
				   dimension = soln.getLiteral("dimension").toString();
			   }
			   
			   if(apparelURI.equals(apparelURIOld)){
				   ApparelSize apparelSize = new ApparelSize(standardVal,sizeValue,dimension);
				   apparelSizes.add(apparelSize);
				   
			   }else{
				   apparelSizes.clear();
				   ApparelSize apparelSize = new ApparelSize(standardVal,sizeValue,dimension);
				   apparelSizes.add(apparelSize);
			   }
			   
			   	
			   if( subtype.equals("Trouser")){ 
				   apparel =  queryTrouser(subtype,apparelURI,apparelSizes,materials,colors,brand);
			   }else{
				   apparel = selectSubtype(subtype,apparelSizes,null,materials,colors,brand,new LinkedList<String>());
			   }
			   
			   if(apparelURI != apparelURIOld ){
				   clothes.add(apparel);
			   }
			   
			   apparelURIOld = apparelURI;
			   
	    };
		return clothes;
	}
	
	public LinkedList<WomenClothing> queryShoes(String clothing,List<String> materials,List<String> colors,String brand,LinkedList<WomenClothing> clothes){
		//LinkedList<WomenClothing> clothes = new LinkedList<WomenClothing>();
		String sizeValue = "";
		String standard = "";
		
		String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
				+                  "PREFIX vocab: <http://localhost:2020/vocab/>"
				+                  ""
				+                  "SELECT ?subtype1 (str(?sizeValue) as ?sizelabel) ?standard {GRAPH arq:UnionGraph {?shoes vocab:shoes_rootId <"+clothing+">."
				+                                                  "?shoes vocab:shoes_productSubType ?subtype1."
				+                                                  "OPTIONAL{"
				+                                                  	"?shoes vocab:shoes_hasShoesSize ?size."
				+                                                  	"?size vocab:shoessize_numericSizeId ?numericId."
				+                                                  	"?numericId vocab:numericsize_numericSizeValue ?sizeValue."
				+                                                 	"?size vocab:shoessize_sizeStandardId ?standardId."
				+                                                  	"?standardId vocab:sizestandard_sizeStandardValue ?standard."
				+                                                  "}."
				+                                                  "}}";
          

		Query query = QueryFactory.create(sparqlQueryString) ;
		QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
		ResultSet results = qexec.execSelect() ;
		
		while (results.hasNext()){
			 
			   QuerySolution soln = results.nextSolution();
			   
			   String subtype = soln.getLiteral("subtype1").toString();
			   
			   if( soln.getLiteral("sizelabel") != null){
				   sizeValue = soln.getLiteral("sizelabel").toString();
			   }
			   if( soln.getLiteral("standard") != null ){
				   standard = soln.getLiteral("standard").toString();
			   }
			   
			   ShoeSize shoeSize = new ShoeSize(standard,Integer.parseInt(sizeValue));
			   WomenClothing shoe = selectSubtype(subtype,new LinkedList<ApparelSize>(),shoeSize,materials,colors,brand,new LinkedList<String>());
			   clothes.add(shoe);
			  
		};
		
		return clothes;
	}
	
	
	public WomenClothing queryTrouser(String type,String apparel,List<ApparelSize> apparelSizes,List<String> materials,List<String> colors,String brand){
		String subtype = null;
		String fastering = null;
		List<String> fasterings = new LinkedList<String>();

		String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
				+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
				+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
				+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
				+ "PREFIX vocab: <http://localhost:2020/vocab/>"
				+ ""
				+ "SELECT * {GRAPH arq:UnionGraph {?trouser vocab:trouser_rootId <"+apparel+">."
			    +								 " ?trouser vocab:trouser_productSubType ?subtype2."
			    +                                " ?trouser vocab:trouser_hasFastening ?fastering.}}";
		
	    
	    Query query = QueryFactory.create(sparqlQueryString) ;
		QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
		ResultSet results = qexec.execSelect() ;
		
		while (results.hasNext()){
			 
			   QuerySolution soln = results.nextSolution();
			   subtype = soln.getLiteral("subtype2").toString();
			   fastering = soln.getLiteral("fastering").toString();
			   fasterings.add(fastering);
			   
		};
		
		return selectSubtype(subtype,apparelSizes,null,materials,colors,brand,fasterings);	
	}
	
	
	public String queryApparelSize(String sizeType,String sizeTypeID){
		String sizeValue = null;
		
	   if(sizeType.equals("numericsize")){	
		   
			String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
					+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
					+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
					+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
					+ "PREFIX vocab: <http://localhost:2020/vocab/>"
					+ ""
					+ "SELECT (str(?sizeValue) as ?sizelabel) {GRAPH arq:UnionGraph "
					+ "     {<http://localhost:2020/"+sizeType+"/"+sizeTypeID+"> vocab:numericsize_numericSizeValue ?sizeValue."
					+ "}}";
		    
		    Query query = QueryFactory.create(sparqlQueryString) ;
			QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
			ResultSet results = qexec.execSelect() ;
			
			while (results.hasNext()){
				 
				   QuerySolution soln = results.nextSolution();
				   sizeValue = soln.getLiteral("sizelabel").toString();
				   
			};
	   
	   }else if(sizeType.equals("labeledsize")){
		   
		   String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
					+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
					+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
					+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
					+ "PREFIX vocab: <http://localhost:2020/vocab/>"
					+ ""
					+ "SELECT (str(?sizeValue) as ?sizelabel) "
					+ "{GRAPH arq:UnionGraph "
					+ " {<http://localhost:2020/"+sizeType+"/"+sizeTypeID+"> vocab:labeledsize_labeledSizeValue ?sizeValue."
					+ "}}";
		   
		    Query query = QueryFactory.create(sparqlQueryString) ;
			QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
			ResultSet results = qexec.execSelect() ;
			
			while (results.hasNext()){
				 
				   QuerySolution soln = results.nextSolution();
				   sizeValue = soln.getLiteral("sizelabel").toString();
		    }
	   }else{
		   
		   
		   String sparqlQueryString = "PREFIX arq: <urn:x-arq:>"
					+ "PREFIX foaf: <http://xmlns.com/foaf/0.1/>"
					+ "PREFIX v: <http://www.w3.org/2006/vcard/ns#>"
					+ "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>"
					+ "PREFIX vocab: <http://localhost:2020/vocab/>"
					+ ""
					+ "SELECT (str(?sizeValue) as ?sizelabel) "
					+ "{GRAPH arq:UnionGraph "
					+ " {<http://localhost:2020/"+sizeType+"/"+sizeTypeID+"> vocab:standardsize_standardSizeValue ?sizeValue."
					+ "}}";
		    
		    Query query = QueryFactory.create(sparqlQueryString) ;
			QueryExecution qexec = QueryExecutionFactory.create(query, dataset);
			ResultSet results = qexec.execSelect() ;
			
			while (results.hasNext()){
				 
				   QuerySolution soln = results.nextSolution();
				   sizeValue = soln.getLiteral("sizelabel").toString();
		   
	         }
	   }
		
		return sizeValue;
		
	}
	
	
	public WomenClothing selectSubtype(String subtype,List<ApparelSize> apparelSizes,ShoeSize shoesize,List<String> materials,List<String> colors,String brand,List<String> fastering){
		WomenClothing clothing = null;
		
		switch (subtype){
		case "Boots":
			clothing = new Boots(materials,colors,subtype,brand,shoesize);
			break;
		case "Occupational":
			clothing = new Occupational(materials,colors,subtype,brand,shoesize);
			break;
		case "Slippers":
			clothing = new Slippers(materials,colors,subtype,brand,shoesize);
			break;
		case "Heels":
			clothing = new Heels(materials,colors,subtype,brand,shoesize);
			break;
		case "Shirt":
			clothing = new Shirt(materials,colors,subtype,brand,apparelSizes);
			break;
		case "Dress":
			clothing = new Dress(materials,colors,subtype,brand,apparelSizes);
			break;
		case "Jeans":
			clothing = new Jeans(materials,colors,subtype,brand,apparelSizes,fastering);
			break;
		case "Pants":
			clothing = new Pants(materials,colors,subtype,brand,apparelSizes,fastering );
			break;
		}
		
		
		return clothing;
		
	}
}
